home *** CD-ROM | disk | FTP | other *** search
/ Alde ADA 1: #1 / CCCC 8804 Volume 1 Number 1 - Alde.iso / C / MISC / FUNC / PROFF.ARC / LTB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-21  |  7.6 KB  |  283 lines

  1. /**
  2.  * ltb.c - Lexical Table Builder
  3.  *
  4.  * Functional description:
  5.  *
  6.  *      This program builds a file containing the data
  7.  *      structures of a compile-time-initialised hash table. 
  8.  *      This hash table may later be used for lexical analysis,
  9.  *      where number of symbols to look up is sufficiently large
  10.  *      to avoid a run-time table initialization.
  11.  *      In order to guarantee the success of this setup, the 
  12.  *      hash routine, the lookup and install routines should be
  13.  *      the same between ltb and the lexical analysis.
  14.  *
  15.  * synopsis:
  16.  *
  17.  *      ltb <input file> [table name]
  18.  *
  19.  * input file format:
  20.  *
  21.  *      <token>  <value identifier> [flag value]
  22.  *
  23.  *      token:          string of alphanumeric characters to be 
  24.  *                      matched by the lexical analyser (no blanks).
  25.  *                      these token strings are "installed" to a hash
  26.  *                      table by ltb to avoid run-time overhead.
  27.  *      value 
  28.  *      identifier:     A constant name to be used internally by the
  29.  *                      lexical analyser in place of the actual
  30.  *                      token value. a "#define <indentifier> <value>"
  31.  *                      is generated for each value identifier, where
  32.  *                      value is an odd and unique integer constant. If
  33.  *                      the value identifier is a `*' (star), then the
  34.  *                      previous value is repeated. Thus:
  35.  *
  36.  *                            token   ident.   flag
  37.  *
  38.  *                              sp      SP      1
  39.  *                              space   *               { inherits SP  }
  40.  *                              blank   *               { inherits SP  }
  41.  *                              .       .       .
  42.  *                              .       .       .
  43.  *
  44.  *      flag value:     An additional integer field to pass flags etc. to
  45.  *                      the lexical analyser. If not specified, set to
  46.  *                      0. token value field must be present for this field
  47.  *                      to be obtained.
  48.  *
  49.  * outputs:
  50.  *
  51.  *      ltb generates two C include files:
  52.  *
  53.  *              [tablename].d:  compile time lexical constants (defines)
  54.  *              [tablename].h:  initialised hash table.
  55.  *
  56.  *      where [tablename] is the name of the hash table as specified
  57.  *      in the command line of ltb. If not specified, "lextab" is used
  58.  *      as a default.
  59.  *
  60.  * routines used by LTB:
  61.  *
  62.  *      hash, lookup and a modified version of install routines,
  63.  *      as defined in K&R, pp. 134 - 136.
  64.  *
  65.  * Application areas:
  66.  *
  67.  *      Lexical analysers for compilers, interpreters, spelling
  68.  *      checkers.
  69.  *
  70.  * Author:
  71.  *      Ozan S. Yigit
  72.  *      Dept. of Computer Science
  73.  *      York University
  74.  *
  75.  */
  76.  
  77. #define MAXLINE         80
  78. #define MAXSYM          80
  79.  
  80. #include <stdio.h>
  81. #include <ctype.h>
  82. #include "lookup.h"
  83.  
  84. static struct lexlist *hashtab[HASHMAX];
  85. static struct lexlist *defitab[HASHMAX];
  86.  
  87. char *tabnam;                          /* table name */
  88.  
  89. main(argc, argv)
  90. int argc;
  91. char *argv[];
  92. {
  93.    FILE *fp;
  94.    char line[MAXLINE];
  95.    char sym[MAXSYM], def[MAXSYM];
  96.    register int val;
  97.    register int prev;
  98.    register char *ptr, *p;
  99.    int flag;
  100.    struct lexlist *np, *lexlook();
  101.  
  102.    if (argc <= 2)
  103.    {
  104.       fprintf(stderr, "%s [-<base>] <symbol file> [tablename]", argv[0]);
  105.       exit(1);
  106.    }
  107.  
  108.    if (*argv[1] == '-')
  109.    {
  110.       val = atoi(argv[1] + 1);         /* skip "-" and convert */
  111.       val = (val & 1) ? val : val + 1;
  112.       p = argv[2];
  113.    }
  114.    else
  115.    {
  116.       val = 1;
  117.       p = argv[1];
  118.    }
  119.  
  120.    if (argc < 3)
  121.       tabnam = "lextab";
  122.    else
  123.       tabnam = argv[argc - 1];
  124.  
  125.    if ((fp = fopen(p, "r")) == NULL)
  126.    {
  127.       fprintf(stderr, "%s:cannot open.\n", argv[1]);
  128.       exit(1);
  129.    }
  130.    else
  131.    {
  132.       prev = val;
  133.       while (fgets(line, MAXLINE, fp) != NULL)
  134.       {
  135.          if (*line != '!')
  136.          {
  137.             flag = 0;
  138.             def[0] = '\0';
  139.             ptr = line;
  140.             while (isspace(*ptr))
  141.                ptr++;
  142.             if (*ptr == '\0')
  143.                continue;
  144.             sscanf(line, "%s %s %d", sym, def, &flag);
  145.             if (!(def[0] == '*' && def[1] == '\0'))
  146.             {
  147.                if ((np = lexlook(def, defitab)) == NULL)
  148.                {
  149.                   /* value define  */
  150.                   lexinstal(def, val, 0, defitab);
  151.                   prev = val;
  152.                   val += 2;
  153.                }
  154.                else
  155.                   prev = np->val;
  156.             }
  157.             /* lexical token */
  158.             lexinstal(sym, prev, flag, hashtab);
  159.          }
  160.       }
  161.       defgen();
  162.       lexgen();
  163.    }
  164. }
  165.  
  166. /*
  167.  * lexgen - print out the hash table in static form
  168.  *
  169.  */
  170. lexgen()
  171. {
  172.    register int i;
  173.    register struct lexlist *np;
  174.    char filebuf[12];
  175.    char *file;
  176.    FILE *op;
  177.  
  178.    file = filebuf;
  179.  
  180.    strncpy(file, tabnam, 8);
  181.    strcat(file, ".h");
  182.  
  183.    if ((op = fopen(file, "w")) == NULL)
  184.    {
  185.       fprintf(stderr, "%s: cannot create.\n", file);
  186.       exit(1);
  187.    }
  188.  
  189.    fprintf(op, "#ifndef STRUC_DEFINED\n\n");
  190.    fprintf(op, "\/\*\t%s\t\*\/\n\n%s\n%s\n%s\n%s\n%s\n", file,
  191.            "struct _lex_h {     char     *__s;",
  192.            "              int      __v;",
  193.            "              int       __f;",
  194.            "        struct  _lex_h  *__l;",
  195.            "};");
  196.    fprintf(op, "\n#define STRUC_DEFINED\n#endif\n");
  197.  
  198.    /*
  199.     * generate the hash table entries. each entry is followed by the next entry
  200.     * in its chain. In the operating systems with memory paging, this should have
  201.     * the extra advantage of localized memory references. 
  202.     */
  203.  
  204.    for (i = 0; i < HASHMAX; i++)
  205.       if ((np = hashtab[i]) != NULL)
  206.          prnode(np, op);
  207.    /*
  208.     * At last, we generate the pointer array (hashtable). this table should be
  209.     * assigned to lextable global variable before using with lexlook() or lexinstal().
  210.     * lextable is defined in lookup.h 
  211.     */
  212.  
  213.    fprintf(op, "\n\n\/\*  Hash Table \*\/\n\n");
  214.    fprintf(op, "struct _lex_h *%s[%d] = {\n\t", tabnam, HASHMAX);
  215.    for (i = 0; i < HASHMAX - 1; i++)
  216.    {
  217.       np = hashtab[i];
  218.       if (np == NULL)
  219.          fprintf(op, "NULL,\t");
  220.       else
  221.          fprintf(op, "\&__%s,\t", np->name);
  222.       if (i % 4 == 0)
  223.          fprintf(op, "\n\t");
  224.    }
  225.    np = hashtab[i];
  226.    if (np == NULL)
  227.       fprintf(op, "NULL  };\n");
  228.    else
  229.       fprintf(op, "\&__%s   };\n", np->name);
  230.  
  231.    fclose(op);
  232. }
  233.  
  234. /*
  235.  * prnode - print the current node. This routine is 
  236.  *          recursive such that printing starts from
  237.  *          the end of the given list
  238.  *
  239.  */
  240. prnode(np, op)
  241. register struct
  242. lexlist *np;
  243. FILE *op;
  244. {
  245.    if (np->link != NULL)
  246.       prnode(np->link, op);
  247.    fprintf(op, "struct\n_lex_h __%s = {  ", np->name);
  248.    fprintf(op, "\"%s\",\n              %6d,%6d,", np->name, np->val, np->flag);
  249.    if (np->link != NULL)
  250.       fprintf(op, "\&__%s };\n", (np->link)->name);
  251.    else
  252.       fprintf(op, "NULL };\n");
  253. }
  254.  
  255. /*
  256.  * defgen - generate a file containing the lexical
  257.  *          constants to be equated to lexical symbols
  258.  */
  259. defgen()
  260. {
  261.    register int i;
  262.    register struct lexlist *np;
  263.    char *file;
  264.    char filebuf[12];
  265.    FILE *op;
  266.  
  267.    file = filebuf;
  268.    strncpy(file, tabnam, 8);
  269.    strcat(file, ".d");
  270.  
  271.    if ((op = fopen(file, "w")) == NULL)
  272.    {
  273.       fprintf(stderr, "%s: cannot create.\n", file);
  274.       exit(1);
  275.    }
  276.    for (i = 0; i < HASHMAX; i++)
  277.    {
  278.       for (np = defitab[i]; np != NULL; np = np->link)
  279.          fprintf(op, "\#define  %s\t%d\n", np->name, np->val);
  280.    }
  281.    fclose(op);
  282. }
  283.